package com.yhcui.rabbit.qrcode;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;

/**
 * 二维码工具类
 *
 * @author yuhui.cui
 * @date 2019-08-28 14:26
 */
@Slf4j
public class QrCodeUtils {

    private static final String FORMAT_NAME = "JPG";

    private static final String CHARACTER_SET = "UTF-8";

    private static Image logoImage = null;


    private QrCodeUtils() {

    }

    /**
     * 初始化
     */
    public static void init () {

        if (logoImage != null) {
            return ;
        }

        ClassPathResource logoResource = new ClassPathResource("/qrcode/logo.png");
//        ClassPathResource logoResource = new ClassPathResource("/qrcode/logo100@20x.png");
        try (InputStream logoStream = logoResource.getInputStream();) {
            logoImage = ImageIO.read(logoStream);
        } catch (Exception e) {
            log.error("init error", e);
        }
    }


    /**
     * input 转为字节
     * @param input
     * @return
     * @throws IOException
     */
    public static byte[] toByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
        return output.toByteArray();
    }

    /**
     * 　生成QRCode图片字节码
     * @param qrcode
     * @param width
     * @param height
     * @return
     */
    public static byte[] genQRCodeImageBytes(String qrcode, int width, int height) {
        try {
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            // 1.定义HashMap hints
            HashMap hints = new HashMap();
            // 2.hints调用put函数设置字符集、间距以及纠错度为M
            hints.put(EncodeHintType.CHARACTER_SET, CHARACTER_SET);
            //纠错等级【L，M，Q，H】
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            hints.put(EncodeHintType.MARGIN, 0);
            BitMatrix bitMatrix = multiFormatWriter.encode(qrcode, BarcodeFormat.QR_CODE, width, height, hints);
            ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
            MatrixToImageWriter.writeToStream(bitMatrix, FORMAT_NAME, pngOutputStream);
            return pngOutputStream.toByteArray();
        } catch (Exception e) {
            log.error("genQRCodeImageBytes error qrcode:{}, width:{}, height:{} Exception:", qrcode, width, height, e);
        }
        return null;
    }

    /**
     * 添加logo到二维码图片中
     * @param data
     * @param needCompressed
     * @return
     * @throws IOException
     */
    public static byte[] addLogoImageToQRCodeBytes(byte[] data,  boolean needCompressed) {

        try {
            BufferedImage qrcodeImage = ImageIO.read(new ByteArrayInputStream(data));
            int qrcodeWidth = qrcodeImage.getWidth(null);
            int qrcodeHeight = qrcodeImage.getHeight(null);
            int logoWidth = logoImage.getWidth(null);
            int logoHight = logoImage.getHeight(null);




            // 压缩logo图片
            if (needCompressed) {
                if (logoWidth > qrcodeWidth) {
                    logoWidth = qrcodeWidth/5;
                }
                if (logoHight > qrcodeHeight) {
                    logoHight = qrcodeHeight/5;
                }

                Image src = logoImage.getScaledInstance(logoWidth, logoWidth, Image.SCALE_SMOOTH);
                BufferedImage tag = new BufferedImage(logoWidth, logoWidth, BufferedImage.TYPE_INT_RGB);
                Graphics2D graphics = tag.createGraphics();
                graphics.drawImage(src, 0, 0, null);
                graphics.dispose();
                logoImage = src;
            }

            // 插入logo图片
            Graphics2D graphics = qrcodeImage.createGraphics();
            int x = (qrcodeWidth - logoWidth) / 2;
            int y = (qrcodeHeight - logoHight) / 2;
            graphics.drawImage(logoImage, x, y, logoWidth, logoHight, null);
            Shape shape = new RoundRectangle2D.Float(x, y, logoWidth, logoHight, 6, 6);
            graphics.setStroke(new BasicStroke(3f));
            graphics.draw(shape);
            graphics.dispose();

            // 带logo二维码返回
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ImageIO.write(qrcodeImage, FORMAT_NAME, bos);
            return bos.toByteArray();
        } catch (Exception e) {
            log.error("addLogoImageToQRCodeBytes error  Exception:", e);
        }
        return data;
    }


    /**
     *
     * image to bytes
     * @param imagePath
     * @return
     */
    public static byte[] imageToByte(String imagePath) {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();) {
            BufferedImage bImage = ImageIO.read(new File(imagePath));
            ImageIO.write(bImage, "png", bos );
            byte [] data = bos.toByteArray();
            return data;
        } catch (Exception e) {
            log.error("imageToByte error Exception:", e);
        }
        return null;
    }

    public static void main(String[] args) throws Exception {
        QrCodeUtils.init();
        byte[] data = QrCodeUtils.genQRCodeImageBytes("发送端sadds12312",400, 400);
        data = QrCodeUtils.addLogoImageToQRCodeBytes(data, false);
        // 内存二维码byte数据输出到磁盘
        // 带logo二维码
        FileOutputStream outputStream = new FileOutputStream("/Users/yuhuicui/tmp/as1234logo.jpg");
        outputStream.write(data);
        outputStream.close();

    }

}
